﻿using System;
using System.Text;
using System.Linq;
using System.Linq.Expressions;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;

namespace user.admin.cyt369.com.services.ORM
{
    /// <summary>
    /// 服务基类
    /// </summary>
    /// <typeparam name="TService"></typeparam>
    public abstract class BaseService<TService> where TService : class, new()
    {
        protected bool AutoCloseContext { get; set; } = true;
        protected static readonly TService m_Instance = new TService();
        /// <summary>
        /// 单实例
        /// </summary>
        public static TService Instance {
            get { return m_Instance; }
        }

        /// <summary>
        /// DBContext对象
        /// </summary>
        protected virtual UserContext Ctx {
            get {
                return new UserContext();
            }
        }

        /// <summary>
        /// 保存对象
        /// </summary>
        /// <param name="course"></param>
        /// <returns></returns>
        protected virtual bool Save<T>(T entity, Expression<Func<T, bool>> predicate = null) where T : class
        {
            if (entity == null)
            {
                throw new ArgumentNullException("entity");
            }
            if (this.AutoCloseContext)
            {
                using (var db = this.Ctx)
                {
                    if (predicate == null)
                    {
                        db.Set<T>().Add(entity);
                        return db.SaveChanges() > 0;
                    }
                    else
                    {
                        var item = db.Set<T>().SingleOrDefault(predicate);
                        if (item == null)
                        {
                            db.Set<T>().Add(entity);
                            return db.SaveChanges() > 0;
                        }
                        else
                        {
                            var propts = entity.GetType().GetProperties();
                            foreach (var p in propts)
                            {
                                p.SetValue(item, p.GetValue(entity, null), null);
                            }
                            db.SaveChanges();
                        }

                        return true;
                    }
                }
            }
            else
            {
                var db = this.Ctx;
                {
                    if (predicate == null)
                    {
                        db.Set<T>().Add(entity);
                        return db.SaveChanges() > 0;
                    }
                    else
                    {
                        var item = db.Set<T>().SingleOrDefault(predicate);
                        if (item == null)
                        {
                            db.Set<T>().Add(entity);
                            return db.SaveChanges() > 0;
                        }
                        else
                        {
                            var propts = entity.GetType().GetProperties();
                            foreach (var p in propts)
                            {
                                p.SetValue(item, p.GetValue(entity, null), null);
                            }
                            db.SaveChanges();
                        }

                        return true;
                    }
                }
            }
        }


        /// <summary>
        /// 更新对象
        /// </summary>
        /// <param name="course"></param>
        /// <returns></returns>
        protected virtual bool Update<T>(T entity, Expression<Func<T, bool>> predicate) where T : class
        {
            if (entity == null)
            {
                throw new ArgumentNullException("entity");
            }

            if (predicate == null)
            {
                throw new ArgumentNullException("selector");
            }

            if (this.AutoCloseContext)
            {
                using (var db = this.Ctx)
                {
                    var item = db.Set<T>().SingleOrDefault(predicate);
                    if (item != null)
                    {
                        var propts = entity.GetType().GetProperties();
                        foreach (var p in propts)
                        {
                            p.SetValue(item, p.GetValue(entity, null), null);
                        }

                        db.SaveChanges();
                        return true;
                    }

                    return false;
                }
            }
            else
            {
                var db = this.Ctx;
                {
                    var item = db.Set<T>().SingleOrDefault(predicate);
                    if (item != null)
                    {
                        var propts = entity.GetType().GetProperties();
                        foreach (var p in propts)
                        {
                            p.SetValue(item, p.GetValue(entity, null), null);
                        }

                        db.SaveChanges();
                        return true;
                    }

                    return false;
                }
            }

        }


        /// <summary>
        /// 删除对象
        /// </summary>
        /// <param name="courseId"></param>
        /// <returns></returns>
        protected virtual bool Delete<T>(T entity) where T : class
        {
            if (entity == null)
            {
                throw new ArgumentNullException("entity");
            }

            if (this.AutoCloseContext)
            {
                using (var db = this.Ctx)
                {
                    db.Set<T>().Remove(entity);
                    db.SaveChanges();
                    return true;
                }
            }
            else
            {
                var db = this.Ctx;
                {
                    db.Set<T>().Remove(entity);
                    db.SaveChanges();
                    return true;
                }
            }

        }

        /// <summary>
        /// 按条件删除
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="predicate"></param>
        /// <returns></returns>
        protected virtual bool Delete<T>(Expression<Func<T, bool>> predicate) where T : class
        {
            if (predicate == null)
            {
                throw new ArgumentNullException("selector");
            }

            if (this.AutoCloseContext)
            {
                using (var db = this.Ctx)
                {
                    var entitys = db.Set<T>().Where(predicate);
                    if (entitys != null)
                    {
                        db.Set<T>().RemoveRange(entitys);
                        db.SaveChanges();
                        return true;
                    }
                }
            }
            else
            {
                var db = this.Ctx;
                {
                    var entitys = db.Set<T>().Where(predicate);
                    if (entitys != null)
                    {
                        db.Set<T>().RemoveRange(entitys);
                        db.SaveChanges();
                        return true;
                    }
                }
            }


            return false;
        }

        /// <summary>
        /// 将对象进行处理后保存数据库
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="predicate"></param>
        /// <param name="action"></param>
        /// <returns></returns>
        protected virtual bool DoAction<T>(Expression<Func<T, bool>> predicate, Action<IQueryable<T>> action) where T : class
        {
            if (predicate == null)
            {
                throw new ArgumentNullException("selector");
            }

            if (action == null)
            {
                throw new ArgumentNullException("action");
            }

            if (this.AutoCloseContext)
            {
                using (var db = this.Ctx)
                {
                    var entitys = db.Set<T>().Where(predicate);
                    if (entitys != null)
                    {
                        action(entitys);
                        db.SaveChanges();
                        return true;
                    }
                }
            }
            else
            {
                var db = this.Ctx;
                {
                    var entitys = db.Set<T>().Where(predicate);
                    if (entitys != null)
                    {
                        action(entitys);
                        db.SaveChanges();
                        return true;
                    }
                }
            }

            return false;
        }

        /// <summary>
        /// 将对象进行处理后保存数据库
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="predicate"></param>
        /// <param name="action"></param>
        /// <returns></returns>
        protected virtual bool DoAction<T>(Expression<Func<T, bool>> predicate, Action<T> action) where T : class
        {
            if (predicate == null)
            {
                throw new ArgumentNullException("selector");
            }

            if (action == null)
            {
                throw new ArgumentNullException("action");
            }

            if (this.AutoCloseContext)
            {
                using (var db = this.Ctx)
                {
                    var entitys = db.Set<T>().Where(predicate).FirstOrDefault();
                    if (entitys != null)
                    {
                        action(entitys);
                        db.SaveChanges();
                        return true;
                    }
                }
            }
            else
            {
                var db = this.Ctx;
                {
                    var entitys = db.Set<T>().Where(predicate).FirstOrDefault();
                    if (entitys != null)
                    {
                        action(entitys);
                        db.SaveChanges();
                        return true;
                    }
                }
            }


            return false;
        }

        /// <summary>
        /// 查询列表
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        protected virtual IQueryable<T> Get<T>(Expression<Func<T, bool>> predicate = null) where T : class
        {
            var db = this.Ctx;

            var query = from o in db.Set<T>()
                        select o;

            if (predicate != null)
            {
                query = query.Where(predicate);
            }

            return query;
        }

        protected virtual IQueryable<TEntity> Get<TEntity, TProperty>(Expression<Func<TEntity, TProperty>> includeExpression, Expression<Func<TEntity, bool>> predicate = null) where TEntity : class
        {
            if (includeExpression == null)
            {
                throw new ArgumentNullException("includeExpression");
            }
            var db = this.Ctx;

            var query = from o in db.Set<TEntity>().Include(includeExpression)
                        select o;

            if (predicate != null)
            {
                query = query.Where(predicate);
            }

            return query;
        }

        /// <summary>
        /// 获取一个对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="predicate"></param>
        /// <returns></returns>
        protected virtual T GetOne<T>(Expression<Func<T, bool>> predicate = null) where T : class
        {
            if (this.AutoCloseContext)
            {
                using (var db = this.Ctx)
                {
                    var query = from o in db.Set<T>()
                                select o;

                    if (predicate != null)
                    {
                        query = query.Where(predicate);
                    }

                    return query.FirstOrDefault();
                }
            }
            else
            {
                var db = this.Ctx;
                {
                    var query = from o in db.Set<T>()
                                select o;

                    if (predicate != null)
                    {
                        query = query.Where(predicate);
                    }

                    return query.FirstOrDefault();
                }
            }

        }

        protected virtual TEntity GetOne<TEntity, TProperty>(Expression<Func<TEntity, TProperty>> includeExpression, Expression<Func<TEntity, bool>> predicate = null) where TEntity : class
        {
            if (includeExpression == null)
            {
                throw new ArgumentNullException("includeExpression");
            }
            if (this.AutoCloseContext)
            {
                using (var db = this.Ctx)
                {
                    var query = from o in db.Set<TEntity>().Include(includeExpression)
                                select o;

                    if (predicate != null)
                    {
                        query = query.Where(predicate);
                    }

                    return query.FirstOrDefault();
                }
            }
            else
            {
                var db = this.Ctx;
                {
                    var query = from o in db.Set<TEntity>().Include(includeExpression)
                                select o;

                    if (predicate != null)
                    {
                        query = query.Where(predicate);
                    }

                    return query.FirstOrDefault();
                }
            }

        }

        /// <summary>
        /// 分页查询
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <typeparam name="TKey"></typeparam>
        /// <param name="page"></param>
        /// <param name="rows"></param>
        /// <param name="total"></param>
        /// <param name="items"></param>
        /// <param name="keySelector"></param>
        /// <returns></returns>
        protected virtual IQueryable<TSource> Pagination<TSource, TKey>(int page, int rows, ref int total, IQueryable<TSource> items, Expression<Func<TSource, TKey>> keySelector, Expression<Func<TSource, TKey>> thenSelector = null, bool isDesc = true, bool isThenDesc = true)
        {
            var orderItems = isDesc ? items.OrderByDescending(keySelector) : items.OrderBy(keySelector);
            if (thenSelector != null)
            {
                orderItems = isThenDesc ? orderItems.ThenByDescending(thenSelector) : orderItems.ThenBy(thenSelector);
            }

            total = items.Count();

            if ((page - 1) > 0)
            {
                items = orderItems.Skip((page - 1) * rows);
                items = items.Take(rows);
            }
            else
            {
                items = orderItems.Take(rows);
            }

            return items;
        }

        protected virtual IQueryable<TSource> Pagination<TSource, TKey1, TKey2>(int page, int rows, ref int total, IQueryable<TSource> items, Expression<Func<TSource, TKey1>> keySelector, Expression<Func<TSource, TKey2>> thenSelector = null, bool isDesc = true, bool isThenDesc = true)
        {
            var orderItems = isDesc ? items.OrderByDescending(keySelector) : items.OrderBy(keySelector);
            if (thenSelector != null)
            {
                orderItems = isThenDesc ? orderItems.ThenByDescending(thenSelector) : orderItems.ThenBy(thenSelector);
            }

            total = items.Count();

            if ((page - 1) > 0)
            {
                items = orderItems.Skip((page - 1) * rows);
                items = items.Take(rows);
            }
            else
            {
                items = orderItems.Take(rows);
            }

            return items;
        }


    }
}
